package com.tuzhi.gateway.filter;

import com.alibaba.fastjson2.JSON;
import com.tuzhi.common.constants.AppConstant;
import com.tuzhi.common.constants.ResultConstant;
import com.tuzhi.common.domain.LoginUserBO;
import com.tuzhi.common.domain.ResultBO;
import com.tuzhi.common.helper.ResultHelper;
import com.tuzhi.gateway.config.GatewayConfig;
import com.tuzhi.gateway.httpclient.face.AuthApi;
import com.tuzhi.gateway.service.ResServiceImpl;
import com.tuzhi.util.ListTzUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.util.List;
import java.util.Set;

import static com.tuzhi.common.constants.security.Constants.AUTHORIZE_TOKEN;
import static com.tuzhi.common.constants.security.Constants.USER_INFO;

/**
 * 给每一个服务的接口结果返回加一个Header：
 * 因为不是每个应用都安装了tuzhi-security这个包，只是tuzhi-auth-sys安装了这个包，
 * 然后网关调用tuzhi-auth-sys在做鉴权（注意这个鉴权是请求过来时，另外发现的鉴权请求，response也是不一样的，跟原请求的区分开的）；
 * 则给每一个服务的接口结果返回加一个Header还是放在网关这里先了
 * <p>
 * 感觉 tuzhi-security（这里有个web过滤器） 不用单独抽出来，tuzhi-auth-sys合在一起就可以了（过滤器直接放在这个项目）
 *
 * @Description token过滤器
 * @date 2019/12/12 13:55
 */
@Slf4j
@Component
public class LoginTokenFilter implements GlobalFilter, Ordered {


    @Autowired
    GatewayConfig gatewayConfig;

    @Resource
    AuthApi authApi;

    @Autowired
    ResServiceImpl resServiceImpl;

    public static final String REFRESH_TOKEN = "Refresh-Token";

    /**
     * token过滤
     *
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String uri = request.getURI().getPath();
        List<String> list = request.getHeaders().get(AUTHORIZE_TOKEN);
        String token = (ListTzUtil.isEmpty(list)) ? "" : list.get(0);
        log.info("source:{}", gatewayConfig.getSource());
        ServerHttpRequest host = exchange.getRequest().mutate().header(AppConstant.source_header_name, gatewayConfig.getSource()).build();
        //将现在的request 变成 change对象
        ServerWebExchange build = exchange.mutate().request(host).build();
        //不需要权限的请求，直接转发访问
        if (notAuth(uri)) {
            response.getHeaders().set(REFRESH_TOKEN, token);
            return chain.filter(build);
        }
        log.info("call checkAuth:uri:{},token:{}", uri, "****");
        ResultBO<LoginUserBO> resultBO;
        try {
            resultBO = authApi.checkAuth(uri, token);//这个方法目前没有权限业务，只判断了token是否有效！！！！！！！使用的是tz-java-frame：：tuzhi-security的过虑器：TuZhiSecurityFilter
            if (resultBO.isSuccess()) {
                LoginUserBO loginUserBO = resultBO.getData();
                if (loginUserBO != null) {
                    String userInfo = URLEncoder.encode(JSON.toJSONString(loginUserBO), "UTF-8");
                    request.mutate().header(USER_INFO, userInfo).build();
                }
            }
        } catch (Exception e) {
            log.error(ExceptionUtils.getStackTrace(e));
            resultBO = ResultHelper.build(ResultConstant.ERR_AUTH_SYS);
        }
        log.info("resultBO:code:{},msg:{}", resultBO.getCode(), resultBO.getMsg());
        if ("0".equals(resultBO.getCode())) {
            String refreshToken = authApi.tokenIsExpRefresh(token);
            response.getHeaders().set(REFRESH_TOKEN, refreshToken);
            return chain.filter(exchange);
        } else {
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            DataBuffer buffer = response.bufferFactory().wrap(JSON.toJSONBytes(resultBO));
            return response.writeWith(Mono.just(buffer));
        }

    }

    @Override
    public int getOrder() {
        return 0;
    }


    static final AntPathMatcher pathMatcher = new AntPathMatcher();

    private boolean notAuth(String url) {
        Set<String> notAuthUrl = resServiceImpl.getNonAuthUrl();
        for (String str : notAuthUrl) {
           /* if (str.contains("*")) {
                String tmp = str.replace("*", ".*");
                if (url.matches(tmp)) {
                    return true;
                }
            } else {
                if (url.startsWith(str)) {
                    return true;
                }
            }*/
            if (pathMatcher.match(str, url)) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        String sr = "/fileStore/api/model/uploads/tuovisual/*";
        String path="/fileStore/api/model/uploads/tuovisual/123";
        System.out.println(pathMatcher.match(sr,path));
    }
}
